package com.fingard.dsp.bank.directbank.cmbc02;

import cmbc.cfca.sm2rsa.common.PKIException;
import cmbc.cfca.util.Base64;
import com.alibaba.fastjson.JSON;
import com.cmbc.unps.util.http.CMBCHttpPostClient;
import com.fingard.constant.Format;
import com.fingard.dsp.DSPSet;
import com.fingard.dsp.bank.directConfig.ActSetItem;
import com.fingard.dsp.bank.directbank.DirectBase;
import com.fingard.dsp.bank.directbank.chinapay01.util.LogUtil;
import com.fingard.dsp.bank.directbank.chinapay01.util.SDKUtil;
import com.fingard.dsp.bank.directbank.chinapay01.util.SecureUtil;
import com.fingard.dsp.bank.directbank.cmbc02.util.Base64Util;
import com.fingard.dsp.bank.directbank.cmbc02.util.ErrorCode;
import com.fingard.dsp.bank.directbank.cmbc02.util.PlatformException;
import com.fingard.dsp.bank.directbank.cmbc02.util.SM2Utils;
import com.fingard.dsp.bank.directbank.cmbc02.util.cert.CertLoader;
import com.fingard.io.FileHelper;
import com.fingard.net.WebRequest;
import com.fingard.text.StringHelper;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.io.*;
import java.net.URLEncoder;
import java.security.PrivateKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;


public class CMBC02Base extends DirectBase {
    public static final String HAED_PARAMS[] = {"version", "source", "merchantNum", "merchantSeq", "transDate", "transTime", "transCode", "securityType", "reserve1", "reserve2", "reserve3",
            "reserve4", "reserve5", "reserveJson"};
    //商户流水号
    public static long seq = 0;

    public String genMerchantSeq(String unps_merchantnum) {
        Date datenow = new Date();
        String dateTime = Format.DateTime16Format.format(datenow);
        String merchantNo = unps_merchantnum;
        int seqLength = 50 - merchantNo.length() - dateTime.length();
        String merchantSeq = merchantNo + String.format("%0" + seqLength + "d", seq) + dateTime; // 仅参考，商户自定义流水号生成
        seq++;
        return merchantSeq;
    }

    /**
     * 解密（返回业务报文）
     *
     * @param merchantNum
     * @param
     * @param responseMap
     * @return
     * @throws PlatformException
     */

    @SuppressWarnings("unchecked")
    public Map<String, Object> decodeMsg(String merchantNum, Map<String, String> responseMap) throws PlatformException {
        if (responseMap == null) {
            return new HashMap<String, Object>();
        } else {
            String businessContext = (String) responseMap.get("businessContext");
            String businessContext_dec = null;
            try {
                businessContext_dec = decodeMsgToString(merchantNum, businessContext);
            } catch (PKIException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            if (businessContext_dec != null && businessContext_dec.length() > 0) {
                return JSON.parseObject(businessContext_dec, Map.class);
            } else {
                return new HashMap<String, Object>();
            }
        }
    }

    /*	**************************/
    public static Map<String, String> paymentConfig = new HashMap<String, String>();

    public static String getConfig(String key) {
        return paymentConfig.get(key);
    }

    public static final String filePath_req = "filePath_req";

    public void initFileContent(Map<String, String> requestMap) throws IOException {
        String fileContentStr = (String) requestMap.get("fileContentStr");
        if (fileContentStr != null && fileContentStr.length() > 0) {
            String merchantSeq = (String) requestMap.get("merchantSeq");
            //String filePath_req = Configuration.getConfig(ConfigConstants.filePath_req);
            String fileName = filePath_req + "/" + merchantSeq + ".txt";
            String[] fileContentStrArray = fileContentStr.split("[/^]");

            File file = new File(fileName);
            FileOutputStream fos = null;
            OutputStreamWriter osw = null;
            BufferedWriter bw = null;
            try {
                File filePath = file.getParentFile();
                if (!filePath.exists()) {
                    filePath.mkdirs();
                }

                fos = new FileOutputStream(file);
                osw = new OutputStreamWriter(fos, "utf-8");
                bw = new BufferedWriter(osw);
                for (int i = 0; i < fileContentStrArray.length; i++) {
                    if (i == 0) {
                        bw.append(fileContentStrArray[i]);
                    } else {
                        bw.newLine();
                        bw.append(fileContentStrArray[i]);
                    }
                }
                bw.newLine();
                bw.flush();
            } catch (IOException e) {
                throw e;
            } finally {
                closeStream(fos, osw, bw);
            }

            String fileContent = null;
            fileContent = Base64Util.fileToBase64(file);
            WriteBankLogLn("fileContent:" + fileContent);

            requestMap.remove("fileContentStr");
            requestMap.put("fileContent", fileContent);
        }
    }

    private void closeStream(FileOutputStream fos, OutputStreamWriter osw, BufferedWriter bw) {
        if (bw != null) {
            try {
                bw.close();
            } catch (Exception e) {
            }
        }
        if (osw != null) {
            try {
                osw.close();
            } catch (Exception e) {
            }
        }
        if (fos != null) {
            try {
                fos.close();
            } catch (Exception e) {
            }
        }
    }


    /*	**************************/


    /**
     * 加密
     *
     * @throws PlatformException
     */
    public String encodeMsgToString(String ownAct, Map<String, String> busiMap) throws PlatformException {
        String busiMapJson = JSON.toJSONString(busiMap);
        WriteBankLogLn2("待签名数据:" + busiMapJson);
        return encodeMsgToString(ownAct, busiMapJson);
    }

    /**
     * 加密
     *
     * @throws PlatformException
     */
    public String encodeMsgToString1(String ownAct, Map<String, Object> busiMap) throws PlatformException {
        String busiMapJson = JSON.toJSONString(busiMap);
        WriteBankLogLn2("待签名数据:" + busiMapJson);
        return encodeMsgToString(ownAct, busiMapJson);
    }

    /*去除请求通知中的空字段*/

    public static void splidReqMap(Map<String, String> requestMap, Map<String, String> headMap, Map<String, String> busiMap) {
        busiMap.putAll(requestMap);
        for (String key : HAED_PARAMS) {
            String value = (String) requestMap.get(key);
            if (!(value == null || value.equals(""))) {
                headMap.put(key, value);
                busiMap.remove(key);
            }
        }
    }

    public static void splidReqMap1(Map<String, Object> requestMap, Map<String, Object> headMap, Map<String, Object> busiMap) {
        busiMap.putAll(requestMap);
        for (String key : HAED_PARAMS) {
            String value = (String) requestMap.get(key);
            if (!(value == null || value.equals(""))) {
                headMap.put(key, value);
                busiMap.remove(key);
            }
        }
    }

    //解析银行的应答通知报文
    public static HashMap<String, String> toHashMap(String p_json) {
        if (StringHelper.isNullOrEmpty(p_json)) {
            return null;
        }
        /*
         * {"appId":"wx1f87d44db95cba7a", "timeStamp":"1486974038762",
         * "status":"0","signType":"MD5",
         * "package":"prepay_id=wx201702131620386486f5e49f0035552369",
         * "callback_url":null, "nonceStr":"1486974038762",
         * "paySign":"7D43672D705CC9E71C034AE6E93546D6"}
         */
        HashMap<String, String> retHashMap = new HashMap<String, String>();

        String[] tmpKeyValues = p_json.split(",");
        for (int i = 0; i < tmpKeyValues.length; i++) {
            String[] keyV = tmpKeyValues[i].split(":");
            String tmpK = StringHelper.trimEnd(keyV[0].trim(), "\"");
            tmpK = StringHelper.trimEnd(tmpK, "}");
            tmpK = StringHelper.trimStart(tmpK, "{");
            tmpK = StringHelper.trimStart(tmpK, "\"");

            String tmpV = StringHelper.trimEnd(keyV[1].trim(), "\"");
            tmpV = StringHelper.trimEnd(tmpV, "}");
            tmpV = StringHelper.trimStart(tmpV, "{");
            tmpV = StringHelper.trimStart(tmpV, "\"");

            retHashMap.put(tmpK.trim(), tmpV);
        }
        return retHashMap;
    }

    /**
     * 功能：将批量文件内容使用DEFLATE压缩算法压缩，Base64编码生成字符串并返回<br>
     * 适用到的交易：批量代付，批量代收，批量退货<br>
     *
     * @param filePath 批量文件-全路径文件名<br>
     * @return
     */
    public static String enCodeFileContent(String filePath, String encoding) {
        String baseFileContent = "";

        File file = new File(filePath);
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                LogUtil.writeErrorLog(e.getMessage(), e);
            }
        }
        InputStream in = null;
        try {
            in = new FileInputStream(file);
            int fl = in.available();
            if (null != in) {
                byte[] s = new byte[fl];
                in.read(s, 0, fl);
                // 压缩编码.
                baseFileContent = new String(SecureUtil.base64Encode(SDKUtil.deflater(s)), encoding);
            }
        } catch (Exception e) {
            LogUtil.writeErrorLog(e.getMessage(), e);
        } finally {
            if (null != in) {
                try {
                    in.close();
                } catch (IOException e) {
                    LogUtil.writeErrorLog(e.getMessage(), e);
                }
            }
        }
        return baseFileContent;
    }


    protected String getCharset() {
        return getBankConfig().getCharset("UTF-8");
    }

    protected String getCharset(String pFor) {
        return getBankConfig().getCharset("UTF-8", pFor);
    }


    public static boolean isBlank(CharSequence cs) {
        int strLen;
        if ((cs == null) || ((strLen = cs.length()) == 0))
            return true;
        for (int i = 0; i < strLen; ++i) {
            if (!(Character.isWhitespace(cs.charAt(i)))) {
                return false;
            }
        }
        return true;
    }


    public String encodeMsgToString(String ownAct, String busiMapJson) throws PlatformException {
        // 1. 先做签名
        String body = busiMapJson;
        String sign = null;
        try {
            // 构建证书对象
            ActSetItem actItem = getBankConfig().getActSetItem(ownAct, "");
            String sm2Path = actItem.ownKeyStorePath;
            WriteBankLogLn2("私钥文件路径:" + sm2Path);
            String sm2Password = actItem.ownKeyPassword;
            WriteBankLogLn2("私钥文件密码:" + sm2Password);
            String certPath = actItem.ownCertFilePath;
            WriteBankLogLn2("公钥文件路径:" + certPath);
            //Cert cert=CertLoader.loadMerchantCert(merchantNum, certPath, sm2Path, sm2Password);
            WriteBankLogLn2("开始加载密钥...");
            PrivateKey privateKey = CertLoader.getSm2PrivateKey(sm2Path, sm2Password);
            WriteBankLogLn2("密钥加载成功,开始签名...");
            sign = SM2Utils.signRaw(null, body, privateKey);
            WriteBankLogLn2("签名成功");
        } catch (UnsupportedEncodingException e) {
            throw new PlatformException(ErrorCode.UNPS_CORE_004, e.getMessage());
        } catch (PKIException e) {
            throw new PlatformException(ErrorCode.UNPS_CORE_004, e.getMessage());
        }

        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put(CMBC02Helper.sign, sign);
        paramMap.put(CMBC02Helper.body, body);

        WriteBankLogLn("sign:" + sign);
        WriteBankLogLn("body:" + body);

        // 2. 再做加密
        String plainTxtBeforeEnc = JSON.toJSONString(paramMap); // 待加密字符串
        String cipherTxt = null;
        String base64 = "";
        try {


            // 构建证书对象

            ActSetItem actItem = getBankConfig().getActSetItem(ownAct, "");
            String pfxFileData = actItem.ownKeyStorePath;
            pfxFileData = DSPSet.replaceFilePath(pfxFileData);
            if (!FileHelper.existFile(pfxFileData)) {
                WriteBankLogLn("证书文件" + pfxFileData + "不存在");
            }
            String pfxFilePwd = actItem.ownKeyPassword;
            String certPath = actItem.oppCertFilePath;

            cipherTxt = SM2Utils.encrypt(ownAct, plainTxtBeforeEnc, certPath);
            base64 = new String(Base64.encode(cipherTxt.getBytes()), "utf-8");
        } catch (UnsupportedEncodingException e) {
            throw new PlatformException(ErrorCode.UNPS_CORE_005, e.getMessage());
        } catch (PKIException e) {
            throw new PlatformException(ErrorCode.UNPS_CORE_005, e.getMessage());
        }
        base64 = base64.replaceAll("\\n", "");
        WriteBankLogLn("businessContext:" + base64);

        return base64;
    }


    @SuppressWarnings("unchecked")
    public String decodeMsgToString(String ownAct, String businessContext) throws PlatformException, PKIException {
        if (isBlank(businessContext)) {
            return null;
        }

        WriteBankLogLn("businessContext:" + businessContext);

        // 1.base64转密文
        businessContext = businessContext.replace("\\n", "");
        String cipherTxt = new String(Base64.decode(businessContext.getBytes()));
        // 2.解密
        String signedTxt = null;

        // 构建证书对象
        ActSetItem actItem = getBankConfig().getActSetItem(ownAct, "");
        String sm2Path = actItem.ownKeyStorePath;
        String sm2Password = actItem.ownKeyPassword;
        PrivateKey privateKey = CertLoader.getSm2PrivateKey(sm2Path, sm2Password);
        String owncert = actItem.ownCertFilePath;


        try {
            signedTxt = SM2Utils.decrypt(cipherTxt, privateKey, owncert);
        } catch (UnsupportedEncodingException e) {
            throw new PlatformException(ErrorCode.UNPS_CORE_006, e.getMessage());
        } catch (PKIException e) {
            throw new PlatformException(ErrorCode.UNPS_CORE_006, e.getMessage());
        }
        // 3.验签
        Map<String, Object> paraMap = JSON.parseObject(signedTxt, Map.class);
        String sign = (String) paraMap.get(CMBC02Helper.sign);
        String body = (String) paraMap.get(CMBC02Helper.body);
        WriteBankLogLn("sign:" + sign);
        WriteBankLogLn("body:" + body);
        boolean signOK = false;
        try {


            String cmbcPath = actItem.oppCertFilePath;


            signOK = SM2Utils.verifyRaw(ownAct, body, sign, cmbcPath);
        } catch (UnsupportedEncodingException e) {
            throw new PlatformException(ErrorCode.UNPS_CORE_007, e.getMessage());
        } catch (PKIException e) {
            throw new PlatformException(ErrorCode.UNPS_CORE_007, e.getMessage());
        }
        if (!signOK) {
            throw new PlatformException(ErrorCode.UNPS_CORE_007, ErrorCode.getErrorMsg(ErrorCode.UNPS_CORE_007));
        }
        return body;
    }


    public static byte[] base64ToStringBytes(String base64) throws UnsupportedEncodingException {
        if (base64 == null || base64.length() == 0)
            return null;

        return Base64.decode(base64.getBytes("UTF-8"));
    }

    public static String base64ToString(String base64) throws UnsupportedEncodingException {
        return new String(base64ToStringBytes(base64), "UTF-8");
    }

    public String getParamStr(Map<String, String> requestParam, String encoding) throws UnsupportedEncodingException {
        if (encoding == null || "".equals(encoding)) {
            encoding = getCharset();
        }
        StringBuffer stringBuffer = new StringBuffer("");
        String reqstr = "";
        if (null != requestParam && 0 != requestParam.size()) {
            for (Entry<String, String> keyMap : requestParam.entrySet()) {
                stringBuffer.append(keyMap.getKey() + "="
                        + (null == keyMap.getValue() || "".equals(keyMap.getValue()) ? "" : URLEncoder.encode((String) keyMap.getValue(), encoding))
                        + "&");
            }
            reqstr = stringBuffer.substring(0, stringBuffer.length() - 1);
        }
        return reqstr;
    }

    protected String[] sendToBank(Map<String, String> p_reqStr, String tmpUrl) throws Exception {
        // TODO Auto-generated method stub
        String[] retStr = new String[]{"", ""};
        String requestStr = null;

        requestStr = getParamStr(p_reqStr, getCharset());

        WriteBankLogLn("进行改变格式的报文：" + requestStr);
        System.out.println(requestStr);

        WriteBankLogLn("提交银行的地址：" + tmpUrl);
        WriteBankLogStep2(p_reqStr.toString());
        WebRequest tmpWebRequest = new WebRequest(tmpUrl);
        tmpWebRequest.setConnectTimeout(100000);
        tmpWebRequest.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
        tmpWebRequest.setRequestProperty("connection", "Close");

        byte[] tmpUpBytes = requestStr.getBytes(getCharset());
        retStr = tmpWebRequest.upload(tmpUpBytes, getCharset());


        WriteBankLogStep3(retStr[1]);
        return retStr;
    }

    public byte[] getMergeBytes(byte[] base, byte[] merge) {
        if (base == null) {
            return merge;
        }
        int baseLengh = base.length;
        int mergeLengh = merge.length;
        byte[] outByte = new byte[baseLengh + mergeLengh];
        for (int i = 0; i < baseLengh; i++) {
            outByte[i] = base[i];
        }
        for (int i = 0; i < mergeLengh; i++) {
            outByte[i + baseLengh] = merge[i];
        }
        return outByte;
    }

    public Map<String, Object> getResponseFromCMBC(Map<String, Object> reqMap, String requestUrl) throws Exception {
        int readTimeOut = getBankConfig().getValueAsInt("readTimeOut");
        WriteBankLogLn("readTimeOut: " + readTimeOut);
        CMBCHttpPostClient httpClient = new CMBCHttpPostClient(requestUrl, readTimeOut, readTimeOut);
        String response = "";
        WriteBankLogLn("httpClient；" + httpClient.getResult());
        try {
            int status = httpClient.send(reqMap, "UTF-8");
            WriteBankLogLn("status:" + status);
            if (status == 200) {
                response = httpClient.getResult();
                WriteBankLogLn("response:" + response);
            }
        } catch (Exception var14) {
            var14.printStackTrace();
        }
        Gson gson = new Gson();
        Map<String, Object> respMap = (Map) gson.fromJson(response, (new TypeToken<Map<String, Object>>() {}).getType());
        return respMap;
    }

    public byte[] getFromBase64(String base64) {
        if (base64 != null && !base64.equals("")) {
            byte[] base = null;

            try {
                base = base64.getBytes("UTF-8");
            } catch (UnsupportedEncodingException var4) {
                var4.printStackTrace();
            }

            return base;
        } else {
            return null;
        }
    }

    /**
     * 返回String字符串转MAP
     *
     * @param
     * @return
     */
    public static Map<String,Object> convertToMap(String srcStr) {
        Map<String,Object> params = new HashMap<String,Object>();

        String[] nodes = srcStr.split(",");
        for (String node : nodes) {
            int index = node.indexOf("=");

            String key = node.substring(0, index);
            String value = node.substring(index+1);

            params.put(key, value);
        }

        return params;
    }

    public static Map<String,Object> convertMapToMap(Map<String,Object> maps) {
        if (maps != null) {
            Map<String,Object> params = new HashMap<String,Object>();
            for (String key : maps.keySet()) {
                Object value = maps.get(key);
                key = key.trim();
                params.put(key, value);
            }
            return params;
        }
        return null;
    }

	/*protected Map<String, String> sendToBank(Map<String, String> p_reqStr,String tmpUrl) throws Exception {
		// TODO Auto-generated method stub
		boolean isProxy=false;
		long start = System.currentTimeMillis();
		String proxyAddress="111.205.207.143";
		int proxyPort=448;
		int connectTimeout = 70000;
		int readTimeout = 70000;
		String requestStr = null;
		String responseStr = "";
		Map<String, String> responseMap = new HashMap<String, String>();

		HttpURLConnection conn = null;
		OutputStream outputStream = null;
		PrintStream printStream = null;
		InputStream inputStream = null;
		InputStreamReader inputStreamReader = null;
		BufferedReader bufferedReader = null;
		try {
			requestStr = getParamStr(p_reqStr, getCharset());
			WriteBankLogLn("发送给银行的通知报文2:" + requestStr);
			URL url = new URL(tmpUrl);
			if (isProxy) {
				InetSocketAddress inetSocketAddress = new InetSocketAddress(proxyAddress, proxyPort);
				Proxy proxy = new Proxy(Proxy.Type.HTTP, inetSocketAddress);
				conn = (HttpURLConnection) url.openConnection(proxy);
			} else {
				conn = (HttpURLConnection) url.openConnection();
			}
			conn.setConnectTimeout(connectTimeout);// 连接超时时间
			conn.setReadTimeout(readTimeout);// 读取结果超时时间
			conn.setDoInput(true); // 可读
			conn.setDoOutput(true); // 可写
			conn.setUseCaches(false);// 取消缓存
			conn.setRequestProperty("Content-type", "application/x-www-form-urlencoded;charset=" + getCharset());
			conn.setRequestMethod("POST");
			if ("https".equalsIgnoreCase(url.getProtocol())) {
				HttpsURLConnection httpsURLConnection = (HttpsURLConnection) conn;
				httpsURLConnection.setSSLSocketFactory(new BaseHttpSSLSocketFactory());
				httpsURLConnection.setHostnameVerifier(new TrustAnyHostnameVerifier());// 解决由于服务器证书问题导致HTTPS无法访问的情况
			}
			conn.connect();

			outputStream = conn.getOutputStream();
			printStream = new PrintStream(outputStream, false, getCharset());
			printStream.print(requestStr);
			printStream.flush();

			StringBuilder stringBuilder = new StringBuilder(2048);
			inputStream = conn.getInputStream();
			inputStreamReader = new InputStreamReader(inputStream, getCharset());

			bufferedReader = new BufferedReader(inputStreamReader);
			String temp = null;
			while (null != (temp = bufferedReader.readLine())) {
				stringBuilder.append(temp);
			}
			int status;
			status = conn.getResponseCode();
			if (PostConstants.status == status) {
				responseStr = stringBuilder.toString();
				// Map<String, Object> responseMap = new HashMap<String, Object>();
				// JSONObject jsonObject = JSON.parseObject(responseStr);
				// for (Entry<String, Object> entry : jsonObject.entrySet()) {
				// responseMap.put(entry.getKey(), entry.getValue());
				// }
				responseMap = UnpsUtils.jsonToStrMap(responseStr);
			}
			return responseMap;
		} catch (IOException e) {
			throw new PlatformException(ErrorCode.UNPS_CORE_003, e.getMessage());
		} finally {
			long end = System.currentTimeMillis();

			WriteBankLogLn("request used:" + (end - start));
			CMBCPostClient.closeStream(outputStream, printStream, inputStream, inputStreamReader, bufferedReader);
			conn.disconnect();
		}
		}*/


}
